<!--
 * @Author: MuQuanyu(MQy)
 * @Date: 2025-10-22 09:53:49
 * @LastEditTime: 2025-10-23 14:13:46
 * @email: muquanyu@outlook.com
-->
<template>
  <div class="dict-manager-box">
    <el-dialog class="custom-dialog" v-model="dialogVisible" :title="isEdit ? '编辑字典数据' : '添加字典数据'"
      :before-close="DialogClose">
      <el-form v-loading="isDialogLoading" style="padding: 15px" ref="dialogFormRef" :model="formData"
        :rules="formDataRules" label-width="auto">
        <el-row justify="space-between">
          <el-col :span="11">
            <el-form-item label="字典数据名称" prop="dictLabel">
              <el-input v-model="formData.dictLabel"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="字典类型" prop="dictTypeID">
              <el-select v-model="formData.dictTypeID" filterable placeholder="请选择类型" style="width: 240px">
                <el-option v-for="item in leftTreeData" :key="item.id" :label="item.dictName" :value="item.id" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row justify="space-between">
          <el-col :span="11">
            <!-- 一般组织数据都不会太多，一次性加载就行 -->
            <el-form-item label="字典数据编码" prop="dictCode">
              <el-input v-model="formData.dictCode"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="排序" prop="sort">
              <el-input type="number" v-model="formData.sort"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row justify="space-between">
          <el-col :span="22">
            <!-- 一般组织数据都不会太多，一次性加载就行 -->
            <el-form-item label="备注" prop="remark">
              <el-input type="textarea" v-model="formData.remark"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row justify="space-between">
          <el-col :span="11">
            <el-form-item label="是否默认" prop="isDefault">
              <el-radio-group v-model="formData.isDefault">
                <el-radio :value="true">是</el-radio>
                <el-radio :value="false">否</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="状态" prop="status">
              <el-radio-group v-model="formData.status">
                <el-radio :value="true">开启</el-radio>
                <el-radio :value="false">禁用</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div class="dialog-bottom" style="display: flex; align-items: center; justify-content: flex-end">
        <el-button :disabled="isDialogLoading" @click="DialogClose">取消</el-button>
        <el-button :disabled="isDialogLoading" type="primary" @click="dialogConfirm">确定</el-button>
      </div>
    </el-dialog>

    <el-dialog class="custom-dialog" v-model="dialogTypeVisible" :title="isTypeEdit ? '编辑字典类型' : '添加字典类型'"
      :before-close="typeDialogClose">
      <el-form v-loading="isDialogLoading" style="padding: 15px" ref="dialogTypeFormRef" :model="typeFormData"
        :rules="typeFormDataRules" label-width="auto">
        <el-row justify="space-between">
          <el-col :span="11">
            <el-form-item label="字典类型名" prop="dictName">
              <el-input v-model="typeFormData.dictName"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="字典类型编码" prop="dictType">
              <el-input v-model="typeFormData.dictType"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row justify="space-between">
          <el-col :span="22">
            <!-- 一般组织数据都不会太多，一次性加载就行 -->
            <el-form-item label="备注" prop="remark">
              <el-input type="textarea" v-model="typeFormData.remark"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row justify="space-between">
          <el-col :span="11">
            <el-form-item label="状态" prop="status">
              <el-radio-group v-model="typeFormData.status">
                <el-radio :value="true">开启</el-radio>
                <el-radio :value="false">禁用</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div class="dialog-bottom" style="display: flex; align-items: center; justify-content: flex-end">
        <el-button :disabled="isTypeDialogLoading" @click="typeDialogClose">取消</el-button>
        <el-button :disabled="isDialogLoading" type="primary" @click="typeDialogConfirm">确定</el-button>
      </div>
    </el-dialog>
    <el-card class="left-card">
      <div class="lc-header">
        <el-input clearable v-model="leftSearchKey" style="width: 240px" placeholder="请输入字典类型" :suffix-icon="Search" />
        <el-dropdown placement="bottom">
          <el-button>
            <el-icon>
              <More />
            </el-icon>
          </el-button>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item @click="showAddTypeDialog">新增字典类型</el-dropdown-item>
              <el-dropdown-item @click="showEditTypeDialog">编辑选中类型</el-dropdown-item>
              <el-dropdown-item @click="cancelCurrentLeftOrgNode">取消选中</el-dropdown-item>
              <el-dropdown-item @click="refreshLeftOrgList">刷新</el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>

      </div>
      <div class="left-tree-outer-box" v-loading="leftDataLoading">
        <el-tree :default-expand-all="isExpandAllLeftOrgNode" :filter-node-method="filterNode" ref="leftOrgRef"
          :data="leftTreeData" :props="defaultProps" highlight-current :current-node-key="currentNodeKey"
          :expand-on-click-node="false" node-key="id" @node-click="handleOrgTreeClick" style="width: 100%">
          <template #empty>
            <div style="display: flex; flex-direction: column; gap: 10px; align-items: center">
              <i class="iconfont icon-kongshuju" style="font-size: 100px"></i>
              <span>空数据</span>
            </div>
          </template>
        </el-tree>
      </div>
    </el-card>
    <el-card class="right-card">
      <div class="rc-top-operator">
        <el-input v-model="rightSearchKey" style="width: 240px" placeholder="请输入字典名" :suffix-icon="Search" />
        <el-button @click="searchRightOrgList">搜索</el-button>
        <el-button @click="showAddDialog" type="primary">添加</el-button>
        <el-button @click="openDleteMBox" type="danger">批量删除</el-button>
        <el-button @click="resetRightOrgList" type="warning">重置</el-button>
      </div>
      <el-table :header-cell-style="{ background: 'var(--yu-div-hover-gray)', color: 'var(--yu-text-color)' }"
        v-loading="tableLoading" class="el-table-outer" border height="calc(100vh - 250px)" ref="orgTableRef"
        :data="tableData" row-key="id" style="width: 100%" @selection-change="handleSelectionChange">
        <template #empty>
          <div style="display: flex; flex-direction: column; gap: 10px; align-items: center">
            <i class="iconfont icon-kongshuju" style="font-size: 100px"></i>
            <span>空数据</span>
          </div>
        </template>
        <!--  :selectable="(row: any) => !selectedItems.includes(row.id)" -->
        <el-table-column type="selection" width="55" />
        <el-table-column label="字典名称" width="120">
          <template #default="scope">{{ scope.row.dictLabel }}</template>
        </el-table-column>
        <el-table-column label="字典类型">
          <template #default="scope">{{leftTreeData.find((x: any) => x.id == scope.row.dictTypeID)?.dictName
          }}</template>

        </el-table-column>
        <el-table-column label="字典编码" property="dictCode"></el-table-column>
        <el-table-column label="默认">
          <template #default="scope">
            <el-tag type="success" v-if="scope.row.isDefault">是</el-tag>
            <el-tag type="danger" v-else>否</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="禁用">
          <template #default="scope">
            <el-tag type="success" v-if="scope.row.status">否</el-tag>
            <el-tag type="danger" v-else>是</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="排序" property="sort"></el-table-column>
        <el-table-column label="操作">
          <template #default="scope">
            <div style="display: flex; align-items: center; gap: 5px; justify-content: center;">
              <el-button type="text" @click="showEditDialog(scope.row.id)">修改</el-button>
              <DeletePopconfirm @handle-delete="deleteSignle" :row-data="scope.row" :loading="isOrgDeleteSingleLoading">

              </DeletePopconfirm>
            </div>
          </template>
        </el-table-column>
      </el-table>
      <div class="custom-pagination-box">
        <el-pagination v-model:current-page="tablePageObj.page" v-model:page-size="tablePageObj.pageSize"
          :page-sizes="[10, 20, 30, 40]" :size="'default'" :disabled="false" :background="false"
          layout="total, sizes, prev, pager, next, jumper" :total="tablePageObj.total" @size-change="handleSizeChange"
          @current-change="handleCurrentChange" />
      </div>

    </el-card>
  </div>
</template>

<script setup lang="ts">

import { Search } from "@element-plus/icons-vue";
import { ElLoading, ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
import { onMounted, reactive, ref, watch } from "vue";
import type { User } from "@/api/sys/user/types";
import { GetUserPage } from "@/api/sys/user";
import DeletePopconfirm from '@/components/DeletePopconfirm/index.vue'
import { DeleteOrg, GetOrgTreeList, OrgDetail } from "@/api/sys/org"
import { AddDictData, AddDictType, DeleteDictData, DictDataDetail, EditDictData, EditDictType, GetDictDataPage, GetDictTypeDetail, GetDictTypeList } from "@/api/sys/dict";

const isExpandAllLeftOrgNode = ref(true)
const leftSearchKey = ref<string>("");
const rightSearchKey = ref<string | null>(null);
const dialogVisible = ref(false);
const sasListDropdown = ref(null)
const defaultProps = {
  children: "children",
  label: "dictName",
};
const leftOrgRef = ref();
const currentNodeKey = ref(null);
const currentNodeType = ref(null)
const leftTreeData = ref<any>();

const handleOrgTreeClick = async (node: any) => {
  if (currentNodeKey.value == node.id) {
    currentNodeKey.value = null;
    currentNodeType.value = null;
    leftOrgRef.value.setCurrentKey(null);

  } else {
    currentNodeKey.value = node.id;
    currentNodeType.value = node.dictType
    leftOrgRef.value.setCurrentKey(node.id);

  }
  await fetchTableData()
  console.log("handleDeptTreeClick", currentNodeKey.value);
};
//#region 添加组织
const DialogClose = () => {
  dialogFormRef.value?.resetFields();
  formData.value = {
    dictTypeID: "",
    dictCode: "",
    dictLabel: "",
    isDefault: false,
    sort: "0",

    remark: "",
    status: true
  }

  dialogVisible.value = false;
};
const showAddDialog = async () => {
  isEdit.value = false;
  dialogVisible.value = true;
  isDialogLoading.value = true;
  await initLeftTreeList()
  isDialogLoading.value = false;
};
const currentEditId = ref<any>(null)
const isDialogLoading = ref(false)
const showEditDialog = async (id: string) => {
  currentEditId.value = id
  isEdit.value = true;
  dialogVisible.value = true;
  isDialogLoading.value = true;
  await initLeftTreeList()
  leftOrgRef.value.filter(leftSearchKey.value.trim()) // 还得过滤
  // 查询组织详情

  let res = await DictDataDetail({ id })
  if (res.code == 200) {
    formData.value = {
      dictTypeID: res.data.dictTypeID,
      dictCode: res.data.dictCode,
      dictLabel: res.data.dictLabel,
      isDefault: res.data.isDefault == 1 ? true : false,
      sort: res.data.sort,
      remark: res.data.remark,
      status: res.data.status == 1 ? true : false
    }
  }

  isDialogLoading.value = false;
}

const dialogFormRef = ref<FormInstance>();
interface FormData {
  dictTypeID: string;
  dictCode: string;
  dictLabel: string;
  isDefault: boolean;
  sort: string;
  remark: string;
  status: boolean;
}
const formData = ref<FormData>({
  dictTypeID: "",
  dictCode: "",
  dictLabel: "",
  isDefault: false,
  sort: "0",
  remark: "",
  status: true
});
const formDataRules = reactive<FormRules<FormData>>({
  dictTypeID: [{ required: true, message: "字典类型必填", trigger: "blur" }],
  dictCode: [{ required: true, message: "字典数据值必填", trigger: "blur" }],
  dictLabel: [{ required: true, message: "字典数据名称必填", trigger: "blur" }],
});
const isEdit = ref(false)
const dialogConfirm = async () => {
  try {
    await dialogFormRef.value?.validate()
  } catch (err: any) {
    return;
  }
  if (isEdit.value) {
    let res: any = await EditDictData({
      id: currentEditId.value,
      dictTypeID: formData.value.dictTypeID,
      dictCode: formData.value.dictCode,
      dictLabel: formData.value.dictLabel,
      isDefault: formData.value.isDefault,
      sort: formData.value.sort.toString(),
      remark: formData.value.remark,
      status: formData.value.status,
    })
    if (res.code == 200) {
      ElMessage.success("修改成功")
    }
  } else {
    let res: any = await AddDictData({
      dictTypeID: formData.value.dictTypeID,
      dictCode: formData.value.dictCode,
      dictLabel: formData.value.dictLabel,
      isDefault: formData.value.isDefault,
      sort: formData.value.sort.toString(),
      remark: formData.value.remark,
      status: formData.value.status,
    })
    if (res.code == 200) {
      ElMessage.success("添加成功")
    }
  }

  DialogClose()
  await initLeftTreeList();
  await fetchTableData();
  leftOrgRef.value.filter(leftSearchKey.value.trim())
}
//#endregion
//#region 组织领导选择
const sasPageObj = ref({
  page: 1,
  pageSize: 10,
  total: 0,
  pages: 0
})
const sasIsLoading = ref(false)
const sasList = ref<User[]>()

const sasLoading = async () => {
  sasIsLoading.value = true;
  try {
    let res: any = await GetUserPage({
      page: sasPageObj.value.page,
      pageSize: sasPageObj.value.pageSize
    })
    if (res.code == 200) {
      if (sasPageObj.value.page == 1) {
        sasList.value = []
      }
      res.data.list.forEach((element: any) => {
        element.title = element.nickname;
        element.imgUrl = element.headPic;
      });
      sasList.value?.push(...res.data.list)
      sasPageObj.value.pages = res.data.pages
      sasPageObj.value.total = res.data.total
    }
  } catch (error) {
    ElMessage.error("加载失败")
  } finally {
    sasIsLoading.value = false;
  }
}
const sasListDropdownVisChange = async (vis: any) => {
  if (vis && sasPageObj.value.page == 1) {
    sasPageObj.value.page = 1
    sasIsLoading.value = true;
    try {
      let res: any = await GetUserPage({
        page: sasPageObj.value.page,
        pageSize: sasPageObj.value.pageSize
      })
      if (res.code == 200) {
        if (sasPageObj.value.page == 1) {
          sasList.value = []
        }
        res.data.list.forEach((element: any) => {
          element.title = element.nickname;
          element.imgUrl = element.headPic;
        });
        sasList.value?.push(...res.data.list)
        sasPageObj.value.page++
        sasPageObj.value.pages = res.data.pages
        sasPageObj.value.total = res.data.total
      }
    } catch (error) {
      ElMessage.error("加载失败")
    } finally {
      sasIsLoading.value = false;
    }
  }
}
const sasListDropdownRef = ref<any>(null)
//#endregion
//#region 上级组织
const orgCascaderLoading = ref<any>(null)
const orgCascaderOptions = ref()
const orgCascaderVisibleChange = async (isShow: any) => {
  if (isShow) {
    // let options = {
    //   target: '.loading',
    //   lock: true,
    //   text: "加载中..."
    // }
    // orgCascaderLoading.value = ElLoading.service(options)
    let res: any = await GetOrgTreeList()
    if (res.code == 200) {
      orgCascaderOptions.value = []
      res.data.forEach((x: any) => {
        orgCascaderOptions.value.push(x)
      });

    }
    // orgCascaderLoading.value.close();
  }
}

//#endregion
//#region 左侧org与table数据
const leftDataLoading = ref(false)
const initLeftTreeList = async () => {
  leftDataLoading.value = true;
  let res: any = await GetDictTypeList({
    searchKey: leftSearchKey.value
  })
  if (res.code == 200) {
    leftTreeData.value = [];
    res.data?.forEach((x: any) => {
      leftTreeData.value.push(x)
    })
  }
  leftDataLoading.value = false;
}
const tableLoading = ref(false)
// 搜索过滤 el-tree
watch(leftSearchKey, (val: string) => {
  leftOrgRef.value.filter(leftSearchKey.value.trim())
})

const filterNode = (value: any, data: any) => {
  if (!value) return true;

  const matchCurrent = data.dictName && data.dictName.includes(value)

  return matchCurrent
}

// 全部展开与折叠
const isTypeEdit = ref(false)
const dialogTypeVisible = ref(false)
const dialogTypeFormRef = ref()
interface TypeFormData {
  dictName: string;
  dictType: string;
  status: boolean;
  remark: string;
}
const typeFormData = ref<TypeFormData>({
  dictName: "",
  dictType: "",
  status: true,
  remark: "",
})
const typeFormDataRules = reactive<FormRules<TypeFormData>>({
  dictName: [{ required: true, message: "字典类型名必填", trigger: "blur" }],
  dictType: [{ required: true, message: "字典类型编码必填", trigger: "blur" }],
});
const isTypeDialogLoading = ref(false)
const showAddTypeDialog = () => {
  isTypeEdit.value = false;
  dialogTypeVisible.value = true;

}
const showEditTypeDialog = async (id: any) => {
  if (!currentNodeKey.value) {
    ElMessage.warning("请先选中一项待修改类型")
    return
  }
  isTypeEdit.value = true;
  dialogTypeVisible.value = true;
  isTypeDialogLoading.value = true;

  let res = await GetDictTypeDetail({ id: currentNodeKey.value })
  if (res.code == 200) {
    typeFormData.value = {
      dictName: res.data.dictName,
      dictType: res.data.dictType,
      status: res.data.status == 1,
      remark: res.data.remark,
    }
  }

  isTypeDialogLoading.value = false;
}
const typeDialogClose = () => {
  dialogTypeFormRef.value?.resetFields();
  typeFormData.value = {
    dictName: "",
    dictType: "",
    status: true,
    remark: "",
  }
  dialogTypeVisible.value = false;
}
const typeDialogConfirm = async () => {
  isTypeDialogLoading.value = true
  if (isTypeEdit.value) {
    let res = await EditDictType({
      ...typeFormData.value,
      id: currentNodeKey.value
    })

    if (res.code == 200) {
      ElMessage.success("编辑成功")
      isTypeDialogLoading.value = false
      dialogTypeVisible.value = false;
    }
  } else {
    let res = await AddDictType(typeFormData.value)
    if (res.code == 200) {
      ElMessage.success("添加成功")
      isTypeDialogLoading.value = false
      dialogTypeVisible.value = false;
    }
  }
  isTypeDialogLoading.value = false
  await refreshLeftOrgList()


}
// 取消选中与刷新
const cancelCurrentLeftOrgNode = async () => {
  if (currentNodeKey.value != null) {
    currentNodeKey.value = null;
    leftOrgRef.value.setCurrentKey(null);
    await fetchTableData()
  }
}
const refreshLeftOrgList = async () => {
  currentNodeKey.value = null;
  leftOrgRef.value.setCurrentKey(null);
  leftDataLoading.value = true
  tableLoading.value = true
  await initLeftTreeList()
  await fetchTableData()
}



// 组织表格分页记录实体
const tablePageObj = reactive({
  page: 1,
  pageSize: 10,
  total: 0,
  pages: 0
})
const tableData = ref<any>(null)
const fetchTableData = async () => {
  tableLoading.value = true;
  let res: any = await GetDictDataPage({
    page: tablePageObj.page,
    pageSize: tablePageObj.pageSize,
    searchKey: rightSearchKey.value,
    dictTypeCode: currentNodeType.value
  })
  if (res.code == 200) {
    tableData.value = [];
    res.data.list.forEach((x: any) => {
      tableData.value.push({
        ...x,
        isDeletedLoading: false
      })
    })
    tablePageObj.total = res.data.total;
    tablePageObj.pages = res.data.pages;
  }
  tableLoading.value = false;
}
const selectedOrgItems = ref<any>([])
const handleSelectionChange = (e: any) => {
  selectedOrgItems.value = e
}
// 分页组件
const handleSizeChange = async (e: any) => {
  sasPageObj.value.pageSize = e
  await fetchTableData()
}
const handleCurrentChange = async (e: any) => {
  sasPageObj.value.page = e
  await fetchTableData()
}
// 删除
const openDleteMBox = async () => {
  if (selectedOrgItems.value.length > 0) {
    ElMessageBox.confirm(
      '确认删除么?',
      '温馨提示',
      {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
    )
      .then(async () => {
        const selectedIds = selectedOrgItems.value.map((x: any) => x.id)
        let res = await DeleteDictData({
          ids: selectedIds
        })
        if (res.code == 200) {
          ElMessage.success("删除成功！")
          await initLeftTreeList()
          await fetchTableData()
        }
      })
      .catch(() => {
      })
  } else {
    ElMessage.warning("请至少选择一项")
  }

}
const isOrgDeleteSingleLoading = ref(false)
const deleteSignle = async (e: any) => {
  console.log(e)
  let res = await DeleteDictData({
    ids: [e.id]
  })
  if (res.code == 200) {
    ElMessage.success("删除成功！")
    await initLeftTreeList()
    await fetchTableData()
  }
  leftOrgRef.value.filter(leftSearchKey.value.trim())
}
// 搜索组织
const searchRightOrgList = async () => {
  if (!tableLoading.value) {
    sasPageObj.value.page = 1
    await fetchTableData()
  }

}
const resetRightOrgList = async () => {
  if (!tableLoading.value) {
    rightSearchKey.value = ""
    await fetchTableData()
  }
}
//#endregion
onMounted(async () => {
  await initLeftTreeList()
  tablePageObj.page = 1
  await fetchTableData()
})
</script>

<style lang="scss" scoped>
.dict-manager-box {
  height: 100%;
  display: flex;
  gap: 5px;

  .left-card {
    flex-grow: 1;
    max-width: 300px;

    .lc-header {
      gap: 5px;
      padding: 20px;
      display: flex;
      align-items: center;
      border-bottom: 1px solid var(--el-card-border-color);
    }

    .left-tree-outer-box {
      padding: 10px;
      overflow-y: auto;
    }
  }

  .right-card {
    flex-grow: 2;
    padding: 20px;
    display: flex;
    flex-direction: column;

    .rc-top-operator {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .el-table-outer {
      margin-top: 20px;
    }
  }
}

::v-deep(.el-card) {
  .el-card__body {
    padding: 0 !important;
  }
}
</style>
